library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;



entity Vga is
    Port ( clk_i : in  STD_LOGIC;
           sw_i  : in  STD_LOGIC_VECTOR (15 downto 0); -- (11 downto 8) is RED, (7 downto 4) is GREEN, (3 downto 0) is BLUE
                                                       -- Writing directly to RAM and from RAM to VGA interface.
                                                       -- Writing when sw_i(15) is high
           -- VGA Output Signals
           vga_hs_o : out  STD_LOGIC; -- Horizontal sync puls to VGA interface
           vga_vs_o : out  STD_LOGIC; -- Vertical sync puls to VGA interface
           vga_red_o    : out  STD_LOGIC_VECTOR (3 downto 0); -- Red to VGA interface
           vga_green_o  : out  STD_LOGIC_VECTOR (3 downto 0); -- Green to VGA interface
           vga_blue_o   : out  STD_LOGIC_VECTOR (3 downto 0) -- Blue to VGA interface
           );
end Vga;


architecture Behavioral of Vga is


-------------------------------------------------------------------------
-- Component Declarations
-------------------------------------------------------------------------

-- 25.2MHz Clock 
COMPONENT clk_wiz_25_2MHz 
PORT (
      clk_in_100MHz:  in STD_LOGIC;
      clk_out_25_2: out STD_LOGIC;
      reset         : in STD_LOGIC;
      locked        : out STD_LOGIC 
      );
END COMPONENT;

-- Ram block for pixels
COMPONENT PIX_RAM
  PORT (
    clka : IN STD_LOGIC;
    ena : IN STD_LOGIC;
    wea : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
    addra : IN STD_LOGIC_VECTOR(18 DOWNTO 0);
    dina : IN STD_LOGIC_VECTOR(11 DOWNTO 0);
    douta : OUT STD_LOGIC_VECTOR(11 DOWNTO 0)
  );
END COMPONENT;



-------------------------------------------------------------
-- Constants for VGA Resolutions
-------------------------------------------------------------

------640x480 60Hz-------  
constant WIDTH : natural := 640;
constant HEIGHT : natural := 480;

constant H_FP : natural := 16; --H front porch width (pixels)
constant H_PW : natural := 96; --H sync pulse width (pixels)
constant H_TOT : natural := 800; --H total period (pixels)

constant V_FP : natural := 10; --V front porch width (lines)
constant V_PW : natural := 2; --V sync pulse width (lines)
constant V_TOT : natural := 525; --V total period (lines)


-------------------------------------------------------------------------
-- VGA signals: Counters, Sync, Red, Gree, Blue
-------------------------------------------------------------------------

-- Activates the screen when it is in the frame area
signal SCREEN_ON  : std_logic;

-- Horizontal and Vertical counters
signal h_count   : std_logic_vector(11 downto 0) := (others =>'0');
signal v_count   : std_logic_vector(11 downto 0) := (others =>'0');

-- signal for the VGA interface
signal vga_red   : std_logic_vector(3 downto 0);
signal vga_blue  : std_logic_vector(3 downto 0);
signal vga_green : std_logic_vector(3 downto 0);

-------------------------------------------------------------------------
-- CLOCK signals
-------------------------------------------------------------------------
signal pxl_clk: std_logic; -- pxl_clk is 25.2MHz
signal reset: std_logic := '0';


-------------------------------------------------------------------------
-- RAM signals
-------------------------------------------------------------------------

signal data_out  : std_logic_vector(11 downto 0) := (others =>'0');
signal data_inn  : std_logic_vector(11 downto 0) := (others =>'0');
signal address   : std_logic_vector(18 downto 0) := (others =>'0');
signal write     : std_logic_vector(0 downto 0) ;


begin

 ---------------------------
 -- PORT MAPS
 --------------------------- 
 
 -- PIXELGENERATOR - pxl_clk=25.2MHz
 PIXELGENERATOR : clk_wiz_25_2MHz PORT MAP
     (--clock inn
      clk_in_100MHz  => clk_i,
      --clock out
      clk_out_25_2 => pxl_clk,
      --reset active high
      reset          => reset,
      --status and controll signals
      locked         => open
     );
     
 -- RAM
      RAM : PIX_RAM PORT MAP
          (
           clka  => clk_i,
           ena  => '1',
           wea  => write,
           addra  => address,
           dina  => data_inn,
           douta  => data_out
          );
     
     

-----------------------------------------------------------------
-- Generate Horizontal, Vertical counters and the Sync signals
-----------------------------------------------------------------
  -- Horizontal counter
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if (h_count = (H_TOT - 1)) then
        h_count <= (others =>'0');
      else
        h_count <= h_count + 1;
      end if;
    end if;
  end process;
  
  -- Vertical counter
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if ((h_count = (H_TOT - 1)) and (v_count = (V_TOT - 1))) then
        v_count <= (others =>'0');
      elsif (h_count = (H_TOT - 1)) then
        v_count <= v_count + 1;
      end if;
    end if;
  end process;
    
  -- Horizontal sync
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if (h_count >= (H_FP + WIDTH - 1)) and (h_count < (H_FP + WIDTH + H_PW - 1)) then
        vga_hs_o <= '1';
      else
        vga_hs_o <= '0';
      end if;
    end if;
  end process;
  
  -- Vertical sync
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if (v_count >= (V_FP + HEIGHT - 1)) and (v_count < (V_FP + HEIGHT + V_PW - 1)) then
        vga_vs_o <= '1';
      else
        vga_vs_o <= '0';
      end if;
    end if;
  end process;
 
 
-------------------------------------------------------
 -- RAM interface
------------------------------------------------------- 
-- Synchronizing reading and writing of adresses with the VGA interface
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if h_count < WIDTH and v_count < HEIGHT then
        address <= address + 1;
      else
        address <= (others =>'0');
      end if;
    end if;
  end process;
  

  

--------------------
-- SCREEN ON
--------------------  
 -- screening signal
 SCREEN_ON <= '1' when h_count < WIDTH and v_count < HEIGHT
           else '0';
			
			
------------------------------------------------------------
-- Turn Off VGA RBG Signals if outside of the active screen
-- Make a 4-bit AND logic with the R, G and B signals
------------------------------------------------------------

 vga_red_o <= (SCREEN_ON & SCREEN_ON & SCREEN_ON & SCREEN_ON) and vga_red;
 vga_green_o <= (SCREEN_ON & SCREEN_ON & SCREEN_ON & SCREEN_ON) and vga_green;
 vga_blue_o <= (SCREEN_ON & SCREEN_ON & SCREEN_ON & SCREEN_ON) and vga_blue;
 
 
 --------------------
 -- Rerouting signals
 --------------------
 vga_red   <= data_out(11 downto 8);
 vga_green <= data_out(7 downto 4);
 vga_blue  <= data_out(3 downto 0);
 
 data_inn <= sw_i(11 downto 0); -- (11 downto 8) is RED, (7 downto 4) is GREEN, (3 downto 0) is BLUE
 write <= sw_i(15 downto 15); -- Activ high when writing to BRAM
			
end Behavioral;		
			
			